【AWS Transit Gateway】複数VPCのアウトバウンド通信を集約する環境を作る
アウトバウンド通信を集約するモチベーション
多くのVPCを稼働させているAWS環境では 「ネットワークセキュリティの統制」が煩雑になりがちです。 特に インターネットへ出ていく通信(アウトバウンド通信) に焦点を当てると、 以下のような要件がよく出てきます。
- アウトバウンド通信のログを集中管理したい
- アウトバウンド通信を一元的に検査および保護したい
各VPC上で独立して Internetゲートウェイ(IGW) および NATゲートウェイ(NATGW) を作成するのが最も直感的です。しかし VPCが増えるにつれて統制や管理コストが肥大してきます。
▲ 図: 各VPC独立でアウトバウンド通信を行う構成。次第に統制・管理コストが大きくなる
そういった背景があり、 アウトバウンド通信をどうにかして集約したい ニーズが出てきます。
▲ 図: アウトバウンド通信をどうにかして集約したい NATGW
Transit Gateway で実現
AWS Transit Gateway(TGW) を使ってアウトバウンド通信の集約を実現します。
TGW はネットワーク間の ハブ接続 を実現するサービスです。 VPCやオンプレ環境のネットワーク(スポーク) を TGW(ハブ) に接続できます。 そして TGW(ハブ) 上でネットワーク(スポーク)間の通信を集中管理します。 ネットワークの接続、ルーティングの運用負荷を軽減できることがメリットです。
どのようにアウトバウンド通信を集約するか 、以下がざっくりとした構成図です。
アウトバウンド通信集約用のVPC を作成して、そこに NATGW環境を作成します。 そして全ての VPCを TGWに接続(Attach)します。 TGWのルーティングで 「アウトバウンド通信は全て NATGW環境へ渡す」 ような設定をいれます。
以上が概要です。 もう少し細かい設計をこれからしていきます。
設計の前提
- アウトバウンド通信を行いたいワークロード環境:
APP-VPC#1 〜 APP-VPC#n
- アウトバウンド通信を行うための NATGW環境:
NAT-VPC
上記 2種のVPC群をベースにした設計をしていきます。 東京リージョンの 2 Availability Zone(AZ) 構成を前提として進めます。 また、 APP-VPC 同士の通信は無い ように作ります。
少し細かい設計(サブネット, TGWアタッチメント編)
サブネット設計
APP-VPC#x
… 2AZ配置、それぞれワークロード用サブネットと TGW用サブネットNAT-VPC
… 2AZ配置、それぞれパブリックサブネットと TGW用サブネット 。 NATGWを配置
上述のようなサブネット構成とします。
TGW用サブネット を用意しているところがポイントです。
これは TGWアタッチメント(後述) 専用の小さなCIDR( /28
など) のサブネットです。
Transit Gateway 設計のベストプラクティス を踏襲しています。
TGWアタッチメント設計
とにもかくにも TGWリソース、およびTGWアタッチメントリソースを作成 するところから TGW活用は始まります。
TGWリソースは以下のような設定で作成しました。
Default route table association:
無効(disable)Default route table propagation:
有効(enable)
つまり、デフォルトルートテーブルを作成しておきます。
そして、TGWアタッチメントからのプロパゲーション(伝播)ルートを
このルートテーブルに自動で反映させます。
(このルートテーブルの活用は 次章 もう少し細かい設計(ルーティング編)
で詳しく説明します)
TGWアタッチメントは VPC単位で作成します 。 作成の際に、サブネットを複数指定できます。 TGW用サブネット 2つ (AZ-A, AZ-C) を指定しましょう。 (TGWは内部的な動作として、指定したサブネットに ネットワークインターフェース: ENI を配置します)。
これで土台は作れました。次章でルート設計を行います。
少し細かい設計(ルーティング編)
TGWルートテーブル設計
TGWアタッチメント(APP-VPC) 用に TGWルートテーブルを 1つ作成しておきます。 このルートテーブルを 各TGWアタッチメント(APP-VPC)に 関連付け(Association) させます。
また、前章でデフォルトルートテーブルを別途作っていました。 これは TGWアタッチメント(NAT-VPC)に 関連付け(Association) させます。 ※ このデフォルトルートテーブルは TGWアタッチメントからの伝播が有効になっていました。 そのため、デフォルトで図のような伝播ルートが生成されています。
ルート設計 (行きの通信)
Workload subnet内 のリソースがインターネットへ出るための
行きの通信
を考えながらルートを設計します。
①: VPCルート(Workload subnet in APP-VPC)
とりあえずデフォルトルートをTGWに向けましょう 。 その後の ルート制御は TGWがやってくれます。
②: TGWルート(APP TGW Route Table)
インターネットに出るためには NAT-VPC へ行くしかありません。 デフォルトルートを TGWアタッチメント(NAT-VPC) に向けましょう。
③: VPCルート(TGW subnet in NAT-VPC)
ここからは、よくある NATGW VPCのルーティングです。 デフォルトルートを NATGWに向けます。 ※ 2AZ構成としているので ルートテーブルは 2つ作ります。
④: VPCルート(Public subnet in NAT-VPC)
通常のパブリックサブネット設定です。 デフォルトルートを Internet Gateway(IGW) に向けます。
ルート設計 (戻りの通信)
インターネットからの 戻りの通信
を考えながらルートを設計します。
①: VPCルート(Public subnet in NAT-VPC)
- 帰り道のゴールは 各APP-VPC の IPアドレス であること
- 帰るためには TGWを経由 する必要があること
上記 2つを意識します。
宛先の CIDRは プレフィクスリスト を活用すると良いでしょう。 複数 CIDRをまとめて管理できます。
宛先(プレフィクスリスト)のターゲットは TGWです。 帰るためには、必ず TGWを経由しないといけません。
②: TGWルート(Default Propagation TGW RouteTable)
ここは デフォルト伝播のルートテーブルを使っているおかげで、 特に追加のルート(staticルート)は必要無い です。 帰りたい APP-VPC へのTGWアタッチメントへ向かってくれます。
③: VPCルート(TGW subnet in APP-VPC)
ここまできたら Workload subnet のリソースへ帰ることができます。 そのため特にルートの追加はありません (デフォルトである localルート)。
追加ルート (APP-VPC間通信の防止)
APP-VPC 同士の通信は無い 要件のために追加設定が必要です。
このままでは、例えば APP-VPC#1
から APP-VPC#2
への通信を試みたときに
NAT-VPCのNATGW経由で接続できてしまいます 。
(参考: この事象の詳細 → Transit Gatewayでインターネットの出口を集約した際の思わぬ弊害とその対応(Blackholeルート) | DevelopersIO )
対策として、 APP TGW RouteTable
に
APP-VPC 宛先の通信をドロップするルート を追加します。
ターゲットを Blackhole とすることで実現できます。 宛先CIDRは PrefixList を使うと便利です。 2020/08 のアップデート で TGWルートテーブルに対しても プレフィクスリストのルートを追加できるようになっています。
ルート設計まとめ
ごちゃってますが、これまでのルート設計を下図にまとめます。
構築してみる
上図のような APP-VPC#1, APP-VPC#2, NAT-VPC からなる アウトバウンド集約環境を作ります。
Terraform を使って構築しました。コードは以下に置いています。
(参考) 作成されるリソース
$ terraform plan | grep "will be created" # aws_ec2_managed_prefix_list.app will be created # aws_ec2_managed_prefix_list_entry.app1 will be created # aws_ec2_managed_prefix_list_entry.app2 will be created # aws_ec2_transit_gateway.main will be created # aws_ec2_transit_gateway_prefix_list_reference.app_blackhole will be created # aws_ec2_transit_gateway_route.app_default will be created # aws_ec2_transit_gateway_route_table.app will be created # aws_ec2_transit_gateway_route_table_association.center will be created # aws_ec2_transit_gateway_vpc_attachment.center will be created # aws_eip.center_a will be created # aws_eip.center_c will be created # aws_internet_gateway.center will be created # aws_nat_gateway.center_a will be created # aws_nat_gateway.center_c will be created # aws_route.center_public_to_igw will be created # aws_route.center_tgw will be created # aws_route.center_tgw_to_natgw_a will be created # aws_route.center_tgw_to_natgw_c will be created # aws_route_table.center_public will be created # aws_route_table.center_tgw_a will be created # aws_route_table.center_tgw_c will be created # aws_route_table_association.center_public_a will be created # aws_route_table_association.center_public_c will be created # aws_route_table_association.center_tgw_a will be created # aws_route_table_association.center_tgw_c will be created # aws_subnet.center_public_a will be created # aws_subnet.center_public_c will be created # aws_subnet.center_tgw_a will be created # aws_subnet.center_tgw_c will be created # aws_vpc.center will be created # module.app1_tgwatt.aws_ec2_transit_gateway_route_table_association.app will be created # module.app1_tgwatt.aws_ec2_transit_gateway_vpc_attachment.app will be created # module.app1_tgwatt.aws_route.app_to_tgw will be created # module.app1_vpc.aws_route_table.private will be created # module.app1_vpc.aws_route_table.tgw will be created # module.app1_vpc.aws_route_table_association.private_a will be created # module.app1_vpc.aws_route_table_association.private_c will be created # module.app1_vpc.aws_route_table_association.tgw_a will be created # module.app1_vpc.aws_route_table_association.tgw_c will be created # module.app1_vpc.aws_security_group.test will be created # module.app1_vpc.aws_subnet.private_a will be created # module.app1_vpc.aws_subnet.private_c will be created # module.app1_vpc.aws_subnet.tgw_a will be created # module.app1_vpc.aws_subnet.tgw_c will be created # module.app1_vpc.aws_vpc.main will be created # module.app2_tgwatt.aws_ec2_transit_gateway_route_table_association.app will be created # module.app2_tgwatt.aws_ec2_transit_gateway_vpc_attachment.app will be created # module.app2_tgwatt.aws_route.app_to_tgw will be created # module.app2_vpc.aws_route_table.private will be created # module.app2_vpc.aws_route_table.tgw will be created # module.app2_vpc.aws_route_table_association.private_a will be created # module.app2_vpc.aws_route_table_association.private_c will be created # module.app2_vpc.aws_route_table_association.tgw_a will be created # module.app2_vpc.aws_route_table_association.tgw_c will be created # module.app2_vpc.aws_security_group.test will be created # module.app2_vpc.aws_subnet.private_a will be created # module.app2_vpc.aws_subnet.private_c will be created # module.app2_vpc.aws_subnet.tgw_a will be created # module.app2_vpc.aws_subnet.tgw_c will be created # module.app2_vpc.aws_vpc.main will be created
確認
「アウトバウンド通信」を確認
EC2インスタンスを APP-VPC#1 および APP-VPC#2 上に配置します。
APP-VPC#1 上のインスタンスへ Session Manager を使って接続します。
curl -I https://dev.classmethod.jp/
を実行してインターネットへのアウトバウンド通信が
できるかどうか確かめてみます。
ちゃんと情報取得できていますね。アウトバウンド通信ができていることを確認できました。
「VPC間通信の防止」を確認
APP-VPC#2 上のインスタンスへ ping を飛ばしてみます。
APP-VPC#1 と APP-VPC#2 との間の通信ができないことを確認しました。 TGWルートテーブルの Blackholeルートが機能していますね。
VPC Reachability Analyzer で色々確認
これは VPC内の接続性テストを行えるサービスです。 ※このサービスの詳細は以下参照ください
早速 このサービスを使って以下に示す接続性テストを行ってみました。
パス | 内容 | 想定する回答 |
---|---|---|
APP-VPC1_to_APP-VPC2 | APP-VPC#1 instance から APP-VPC#2 instance への接続テスト |
到達不可能 |
APP-VPC1_to_Internet | APP-VPC#1 instance から Internet(IGW) への接続テスト |
到達可能 |
NATGW_to_APP-VPC1 | NATGW からなる APP-VPC#1 instance への接続テスト |
到達可能 |
結果はこちら。想定通りになりました。
APP-VPC1_to_APP-VPC2
詳細
以下のように「到達不可能である理由」を表示してくれます。
Transit Gateway ルートテーブル
tgw-rtb-019d812f20af61b09
にはtgw-attach-037e474c52768c3de
への適切なルートがありません。
tgw-rtb-019d812f20af61b09
は TGWアタッチメント(for APP-VPC) に関連付けていたルートテーブルでした。
以下のように Blackholeルートを入れていることが到達不可能の原因となります。
APP-VPC1_to_Internet
詳細
到達可能である場合は、以下のようにパスが表示されます。TGW経由で IGWへ接続できることを確認できます。
NATGW_to_APP-VPC1
詳細
NATGWからの 戻りの通信も到達可能です。以下のようなパスとなります。
VPC Network Access Analyzer で色々確認
これは ネットワークインターフェース間のパスを分析してくれるサービスです。 ※このサービスの詳細は以下参照ください
早速使用してみます。使用開始時にデフォルトで作成されている 4つのスコープの内 AWS-IGW-Egress(IGWへのアウトバウンドパスの特定) を選択して、結果を見てみます。
結果はこちら。
「 instance-APP-VPC#1 から nwinfra-dev-center-igw
へのパス」、および
「 instance-APP-VPC#2 から nwinfra-dev-center-igw
へのパス」が表示されていることが分かります。
(同じ内容のパス?が 重複して表示されている原因は分かりませんでした)
結果を選択すると VPC Reachability Analyzer と同じようにパスが表示されます。
この AWS-IGW-Egress
の結果からも APP-VPC
から NAT-VPC
経由で
アウトバウンド通信を行えることを確認できました。
おわりに
Transit Gateway を活用して、アウトバウンド通信を集約する環境を作成してみました。
このあとの拡張として Network Firewall によるアウトバウンド通信の検査や、 VPC Flow Logs によるアウトバウンド通信ログの集中管理が考えられます。
▲ 図: Network Firewall および VPC Flow Logs の導入イメージ
これら集中管理の恩恵を受けるためにも、Transit Gateway の各要素 やネットワークルーティングの理解は大事です。 最初はルート設計が少し煩雑に感じるかも知れません。 行きの通信だけではなく、戻りの通信も考慮することが大事です。